package main;

import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

import comunicacao.ReceiveMessageInterface;
import entities.Range;
import entities.ServerInfo;

/**
 * Utilidades disponiveis ao controlador primário
 * 
 * @author Leonardo Lino Nº45340
 * @author Diogo Pires Nº40351
 */
public class MasterUtils {
	
	public static void sendStartConditions(ServerInfo targetServer, ServerInfo provider, ServerInfo providerReplic, ServerInfo coordinator, Range mainRange, Range coordinatorRange, Range replicRange, int shardingLevel){
		Registry registry;
		ReceiveMessageInterface dbServer;
		String dbRegistryName = targetServer.getBindName();
		
        try {
			registry = LocateRegistry.getRegistry(targetServer.getAddress(), targetServer.getPort());
            dbServer = (ReceiveMessageInterface) (registry.lookup(dbRegistryName));
        
            if(shardingLevel == 0)
            	dbServer.loadDatabase(null, null, null, mainRange, null, null, shardingLevel);
            else if(shardingLevel == 1)
            	dbServer.loadDatabase(provider, null, null, mainRange, coordinatorRange, replicRange, shardingLevel);
            else
            	dbServer.loadDatabase(provider, providerReplic, coordinator, mainRange, coordinatorRange, replicRange, shardingLevel);
        
        } catch (RemoteException e) {
        	System.out.println("Error: in MasterUtils.assingResponsibilities");
        	e.printStackTrace();
        } catch (NotBoundException e) {
            System.out.println("Error: in MasterUtils.assingResponsibilities");
        }
	}
	
	public static void sendRemovalConditions(ServerInfo targetServer, ServerInfo departedCoordinator, ServerInfo replic, Range mainRange, Range coordinatorRange, Range replicRange, int removalLevel){
		Registry registry;
		ReceiveMessageInterface dbServer;
		String dbRegistryName = targetServer.getBindName();
		
        try {
			registry = LocateRegistry.getRegistry(targetServer.getAddress(), targetServer.getPort());
            dbServer = (ReceiveMessageInterface) (registry.lookup(dbRegistryName));
            
            if(removalLevel == 2)
            	dbServer.ReorganizeDatabase(null, null, mainRange, null, null, removalLevel);
            else
            	dbServer.ReorganizeDatabase(departedCoordinator, replic, mainRange, coordinatorRange, replicRange, removalLevel);
       
        } catch (RemoteException e) {
        	System.out.println("Error: in MasterUtils.assingResponsibilities (Removal)");
        	e.printStackTrace();
        } catch (NotBoundException e) {
            System.out.println("Error: in MasterUtils.assingResponsibilities (Removal)");
        }
	}
	
	public static Range calculateMainRange (Range range, int responsible, int maxNumTheaters){
		int min = range.getMin();
		int max = range.getMax();
		int size = range.getSize();
		
		if(max > min){
			//if size is even
			if ( (size & 1) == 0 )
				return new Range(min + (size/2), max, responsible, maxNumTheaters);
			else
				return new Range(min + (size/2), max, responsible, maxNumTheaters);
		}else{
			int half = size / 2;
			int newMin = min + half;
			
			if( (newMin) > maxNumTheaters){
				newMin = newMin - maxNumTheaters;
			}
			
			//if size is even
			if ( (size & 1) == 0 ){
				return new Range(newMin, max, responsible, maxNumTheaters);
			}else
				return new Range(newMin, max, responsible, maxNumTheaters);
		}
	}
	
	public static Range calculateReplicRange (Range range, int responsible, int maxNumTheaters){
		int min = range.getMin();
		int max = range.getMax();
		int size = range.getSize();
		
		if(max > min){
			//if size is even
			if ( (size & 1) == 0 )
				return new Range(min, min + (size/2) - 1 , responsible, maxNumTheaters);
			else
				return new Range(min, min + (size/2) - 1, responsible, maxNumTheaters);
		}else{
			int half = size / 2;
			int newMin = min + half - 1;
			
			if( (newMin) > maxNumTheaters){
					newMin = newMin - maxNumTheaters;
			}
			
			
			//if size is even
			if ( (size & 1) == 0 ){
				return new Range(min, newMin, responsible, maxNumTheaters);
			}else
				return new Range(min, newMin, responsible, maxNumTheaters);
		}
	}
	
	/**
	 * Merges two adjacent ranges
	 * @param range 		- lower adjacent range
	 * @param range2 		- Higher adjacent range
	 * @param responsible	- Responsible for the range
	 * 
	 * @return a new range that combines the two provided ranges
	 */
	public static Range calculateMergeRange (Range range, Range range2, int responsible){
		return new Range(range.getMin(), range2.getMax(), responsible, range.getMaxTheaters());
	}
}
